WOLF core
WOLF: A Modular Estimation Framework for Robotics
XXXXXXXXXXXXXXXXXXXXXXXXvoid(0)" frameborder="0" name="MSearchResults" id="MSearchResults">
jet.h
Go to the documentation of this file.
1// This is not part of WOLF
2// clang-format off
3//
4// Adapted from Ceres Solver 2.2.0 (include/ceres/jet.h) so that WOLF autodiff does not
5// require Ceres: namespace 'ceres' renamed to 'wolf::autodiff', and 'CERES_' macros and include
6// guards renamed to 'WOLF_AUTODIFF_'. The original license follows.
7//
8// Ceres Solver - A fast non-linear least squares minimizer
9// Copyright 2023 Google Inc. All rights reserved.
10// http://ceres-solver.org/
11//
12// Redistribution and use in source and binary forms, with or without
13// modification, are permitted provided that the following conditions are met:
14//
15// * Redistributions of source code must retain the above copyright notice,
16// this list of conditions and the following disclaimer.
17// * Redistributions in binary form must reproduce the above copyright notice,
18// this list of conditions and the following disclaimer in the documentation
19// and/or other materials provided with the distribution.
20// * Neither the name of Google Inc. nor the names of its contributors may be
21// used to endorse or promote products derived from this software without
22// specific prior written permission.
23//
24// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
35//
36// Author: keir@google.com (Keir Mierle)
37//
38// A simple implementation of N-dimensional dual numbers, for automatically
39// computing exact derivatives of functions.
40//
41// While a complete treatment of the mechanics of automatic differentiation is
42// beyond the scope of this header (see
43// http://en.wikipedia.org/wiki/Automatic_differentiation for details), the
44// basic idea is to extend normal arithmetic with an extra element, "e," often
45// denoted with the greek symbol epsilon, such that e != 0 but e^2 = 0. Dual
46// numbers are extensions of the real numbers analogous to complex numbers:
47// whereas complex numbers augment the reals by introducing an imaginary unit i
48// such that i^2 = -1, dual numbers introduce an "infinitesimal" unit e such
49// that e^2 = 0. Dual numbers have two components: the "real" component and the
50// "infinitesimal" component, generally written as x + y*e. Surprisingly, this
51// leads to a convenient method for computing exact derivatives without needing
52// to manipulate complicated symbolic expressions.
53//
54// For example, consider the function
55//
56// f(x) = x^2 ,
57//
58// evaluated at 10. Using normal arithmetic, f(10) = 100, and df/dx(10) = 20.
59// Next, argument 10 with an infinitesimal to get:
60//
61// f(10 + e) = (10 + e)^2
62// = 100 + 2 * 10 * e + e^2
63// = 100 + 20 * e -+-
64// -- |
65// | +--- This is zero, since e^2 = 0
66// |
67// +----------------- This is df/dx!
68//
69// Note that the derivative of f with respect to x is simply the infinitesimal
70// component of the value of f(x + e). So, in order to take the derivative of
71// any function, it is only necessary to replace the numeric "object" used in
72// the function with one extended with infinitesimals. The class Jet, defined in
73// this header, is one such example of this, where substitution is done with
74// templates.
75//
76// To handle derivatives of functions taking multiple arguments, different
77// infinitesimals are used, one for each variable to take the derivative of. For
78// example, consider a scalar function of two scalar parameters x and y:
79//
80// f(x, y) = x^2 + x * y
81//
82// Following the technique above, to compute the derivatives df/dx and df/dy for
83// f(1, 3) involves doing two evaluations of f, the first time replacing x with
84// x + e, the second time replacing y with y + e.
85//
86// For df/dx:
87//
88// f(1 + e, y) = (1 + e)^2 + (1 + e) * 3
89// = 1 + 2 * e + 3 + 3 * e
90// = 4 + 5 * e
91//
92// --> df/dx = 5
93//
94// For df/dy:
95//
96// f(1, 3 + e) = 1^2 + 1 * (3 + e)
97// = 1 + 3 + e
98// = 4 + e
99//
100// --> df/dy = 1
101//
102// To take the gradient of f with the implementation of dual numbers ("jets") in
103// this file, it is necessary to create a single jet type which has components
104// for the derivative in x and y, and passing them to a templated version of f:
105//
106// template<typename T>
107// T f(const T &x, const T &y) {
108// return x * x + x * y;
109// }
110//
111// // The "2" means there should be 2 dual number components.
112// // It computes the partial derivative at x=10, y=20.
113// Jet<double, 2> x(10, 0); // Pick the 0th dual number for x.
114// Jet<double, 2> y(20, 1); // Pick the 1st dual number for y.
115// Jet<double, 2> z = f(x, y);
116//
117// LOG(INFO) << "df/dx = " << z.v[0]
118// << "df/dy = " << z.v[1];
119//
120// Most users should not use Jet objects directly; a wrapper around Jet objects,
121// which makes computing the derivative, gradient, or jacobian of templated
122// functors simple, is in autodiff.h. Even autodiff.h should not be used
123// directly; instead autodiff_cost_function.h is typically the file of interest.
124//
125// For the more mathematically inclined, this file implements first-order
126// "jets". A 1st order jet is an element of the ring
127//
128// T[N] = T[t_1, ..., t_N] / (t_1, ..., t_N)^2
129//
130// which essentially means that each jet consists of a "scalar" value 'a' from T
131// and a 1st order perturbation vector 'v' of length N:
132//
133// x = a + \sum_i v[i] t_i
134//
135// A shorthand is to write an element as x = a + u, where u is the perturbation.
136// Then, the main point about the arithmetic of jets is that the product of
137// perturbations is zero:
138//
139// (a + u) * (b + v) = ab + av + bu + uv
140// = ab + (av + bu) + 0
141//
142// which is what operator* implements below. Addition is simpler:
143//
144// (a + u) + (b + v) = (a + b) + (u + v).
145//
146// The only remaining question is how to evaluate the function of a jet, for
147// which we use the chain rule:
148//
149// f(a + u) = f(a) + f'(a) u
150//
151// where f'(a) is the (scalar) derivative of f at a.
152//
153// By pushing these things through sufficiently and suitably templated
154// functions, we can do automatic differentiation. Just be sure to turn on
155// function inlining and common-subexpression elimination, or it will be very
156// slow!
157//
158// WARNING: Most Ceres users should not directly include this file or know the
159// details of how jets work. Instead the suggested method for automatic
160// derivatives is to use autodiff_cost_function.h, which is a wrapper around
161// both jets.h and autodiff.h to make taking derivatives of cost functions for
162// use in Ceres easier.
163
164#ifndef WOLF_AUTODIFF_PUBLIC_JET_H_
165#define WOLF_AUTODIFF_PUBLIC_JET_H_
166
167#include <cmath>
168#include <complex>
169#include <iosfwd>
170#include <iostream> // NOLINT
171#include <limits>
172#include <numeric>
173#include <string>
174#include <type_traits>
175
176#include "Eigen/Core"
180
181// Here we provide partial specializations of std::common_type for the Jet class
182// to allow determining a Jet type with a common underlying arithmetic type.
183// Such an arithmetic type can be either a scalar or an another Jet. An example
184// for a common type, say, between a float and a Jet<double, N> is a Jet<double,
185// N> (i.e., std::common_type_t<float, wolf::autodiff::Jet<double, N>> and
186// wolf::autodiff::Jet<double, N> refer to the same type.)
187//
188// The partial specialization are also used for determining compatible types by
189// means of SFINAE and thus allow such types to be expressed as operands of
190// logical comparison operators. Missing (partial) specialization of
191// std::common_type for a particular (custom) type will therefore disable the
192// use of comparison operators defined by Ceres.
193//
194// Since these partial specializations are used as SFINAE constraints, they
195// enable standard promotion rules between various scalar types and consequently
196// their use in comparison against a Jet without providing implicit
197// conversions from a scalar, such as an int, to a Jet (see the implementation
198// of logical comparison operators below).
199
200template <typename T, int N, typename U>
201struct std::common_type<T, wolf::autodiff::Jet<U, N>> {
203};
204
205template <typename T, int N, typename U>
206struct std::common_type<wolf::autodiff::Jet<T, N>, U> {
208};
209
210template <typename T, int N, typename U>
211struct std::common_type<wolf::autodiff::Jet<T, N>, wolf::autodiff::Jet<U, N>> {
213};
214
215namespace wolf::autodiff {
216
217template <typename T, int N>
218struct Jet {
219 enum { DIMENSION = N };
220 using Scalar = T;
221
222 // Default-construct "a" because otherwise this can lead to false errors about
223 // uninitialized uses when other classes relying on default constructed T
224 // (where T is a Jet<T, N>). This usually only happens in opt mode. Note that
225 // the C++ standard mandates that e.g. default constructed doubles are
226 // initialized to 0.0; see sections 8.5 of the C++03 standard.
227 Jet() : a() { v.setConstant(Scalar()); }
228
229 // Constructor from scalar: a + 0.
230 explicit Jet(const T& value) {
231 a = value;
232 v.setConstant(Scalar());
233 }
234
235 // Constructor from scalar plus variable: a + t_i.
236 Jet(const T& value, int k) {
237 a = value;
238 v.setConstant(Scalar());
239 v[k] = T(1.0);
240 }
241
242 // Constructor from scalar and vector part
243 // The use of Eigen::DenseBase allows Eigen expressions
244 // to be passed in without being fully evaluated until
245 // they are assigned to v
246 template <typename Derived>
247 EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived>& v)
248 : a(a), v(v) {}
249
250 // Compound operators
252 *this = *this + y;
253 return *this;
254 }
255
257 *this = *this - y;
258 return *this;
259 }
260
262 *this = *this * y;
263 return *this;
264 }
265
267 *this = *this / y;
268 return *this;
269 }
270
271 // Compound with scalar operators.
272 Jet<T, N>& operator+=(const T& s) {
273 *this = *this + s;
274 return *this;
275 }
276
277 Jet<T, N>& operator-=(const T& s) {
278 *this = *this - s;
279 return *this;
280 }
281
282 Jet<T, N>& operator*=(const T& s) {
283 *this = *this * s;
284 return *this;
285 }
286
287 Jet<T, N>& operator/=(const T& s) {
288 *this = *this / s;
289 return *this;
290 }
291
292 // The scalar part.
293 T a;
294
295 // The infinitesimal part.
296 Eigen::Matrix<T, N, 1> v;
297
298 // This struct needs to have an Eigen aligned operator new as it contains
299 // fixed-size Eigen types.
300 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
301};
302
303// Unary +
304template <typename T, int N>
305inline Jet<T, N> const& operator+(const Jet<T, N>& f) {
306 return f;
307}
308
309// TODO(keir): Try adding __attribute__((always_inline)) to these functions to
310// see if it causes a performance increase.
311
312// Unary -
313template <typename T, int N>
315 return Jet<T, N>(-f.a, -f.v);
316}
317
318// Binary +
319template <typename T, int N>
320inline Jet<T, N> operator+(const Jet<T, N>& f, const Jet<T, N>& g) {
321 return Jet<T, N>(f.a + g.a, f.v + g.v);
322}
323
324// Binary + with a scalar: x + s
325template <typename T, int N>
326inline Jet<T, N> operator+(const Jet<T, N>& f, T s) {
327 return Jet<T, N>(f.a + s, f.v);
328}
329
330// Binary + with a scalar: s + x
331template <typename T, int N>
332inline Jet<T, N> operator+(T s, const Jet<T, N>& f) {
333 return Jet<T, N>(f.a + s, f.v);
334}
335
336// Binary -
337template <typename T, int N>
338inline Jet<T, N> operator-(const Jet<T, N>& f, const Jet<T, N>& g) {
339 return Jet<T, N>(f.a - g.a, f.v - g.v);
340}
341
342// Binary - with a scalar: x - s
343template <typename T, int N>
344inline Jet<T, N> operator-(const Jet<T, N>& f, T s) {
345 return Jet<T, N>(f.a - s, f.v);
346}
347
348// Binary - with a scalar: s - x
349template <typename T, int N>
350inline Jet<T, N> operator-(T s, const Jet<T, N>& f) {
351 return Jet<T, N>(s - f.a, -f.v);
352}
353
354// Binary *
355template <typename T, int N>
356inline Jet<T, N> operator*(const Jet<T, N>& f, const Jet<T, N>& g) {
357 return Jet<T, N>(f.a * g.a, f.a * g.v + f.v * g.a);
358}
359
360// Binary * with a scalar: x * s
361template <typename T, int N>
362inline Jet<T, N> operator*(const Jet<T, N>& f, T s) {
363 return Jet<T, N>(f.a * s, f.v * s);
364}
365
366// Binary * with a scalar: s * x
367template <typename T, int N>
368inline Jet<T, N> operator*(T s, const Jet<T, N>& f) {
369 return Jet<T, N>(f.a * s, f.v * s);
370}
371
372// Binary /
373template <typename T, int N>
374inline Jet<T, N> operator/(const Jet<T, N>& f, const Jet<T, N>& g) {
375 // This uses:
376 //
377 // a + u (a + u)(b - v) (a + u)(b - v)
378 // ----- = -------------- = --------------
379 // b + v (b + v)(b - v) b^2
380 //
381 // which holds because v*v = 0.
382 const T g_a_inverse = T(1.0) / g.a;
383 const T f_a_by_g_a = f.a * g_a_inverse;
384 return Jet<T, N>(f_a_by_g_a, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
385}
386
387// Binary / with a scalar: s / x
388template <typename T, int N>
389inline Jet<T, N> operator/(T s, const Jet<T, N>& g) {
390 const T minus_s_g_a_inverse2 = -s / (g.a * g.a);
391 return Jet<T, N>(s / g.a, g.v * minus_s_g_a_inverse2);
392}
393
394// Binary / with a scalar: x / s
395template <typename T, int N>
396inline Jet<T, N> operator/(const Jet<T, N>& f, T s) {
397 const T s_inverse = T(1.0) / s;
398 return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
399}
400
401// Binary comparison operators for both scalars and jets. At least one of the
402// operands must be a Jet. Promotable scalars (e.g., int, float, double etc.)
403// can appear on either side of the operator. std::common_type_t is used as an
404// SFINAE constraint to selectively enable compatible operand types. This allows
405// comparison, for instance, against int literals without implicit conversion.
406// In case the Jet arithmetic type is a Jet itself, a recursive expansion of Jet
407// value is performed.
408#define WOLF_AUTODIFF_DEFINE_JET_COMPARISON_OPERATOR(op) \
409 template <typename Lhs, \
410 typename Rhs, \
411 std::enable_if_t<PromotableJetOperands_v<Lhs, Rhs>>* = nullptr> \
412 constexpr bool operator op(const Lhs& f, const Rhs& g) noexcept( \
413 noexcept(internal::AsScalar(f) op internal::AsScalar(g))) { \
414 using internal::AsScalar; \
415 return AsScalar(f) op AsScalar(g); \
416 }
423#undef WOLF_AUTODIFF_DEFINE_JET_COMPARISON_OPERATOR
424
425// Pull some functions from namespace std.
426//
427// This is necessary because we want to use the same name (e.g. 'sqrt') for
428// double-valued and Jet-valued functions, but we are not allowed to put
429// Jet-valued functions inside namespace std.
430using std::abs;
431using std::acos;
432using std::asin;
433using std::atan;
434using std::atan2;
435using std::cbrt;
436using std::ceil;
437using std::copysign;
438using std::cos;
439using std::cosh;
440using std::erf;
441using std::erfc;
442using std::exp;
443using std::exp2;
444using std::expm1;
445using std::fdim;
446using std::floor;
447using std::fma;
448using std::fmax;
449using std::fmin;
450using std::fpclassify;
451using std::hypot;
452using std::isfinite;
453using std::isinf;
454using std::isnan;
455using std::isnormal;
456using std::log;
457using std::log10;
458using std::log1p;
459using std::log2;
460using std::norm;
461using std::pow;
462using std::signbit;
463using std::sin;
464using std::sinh;
465using std::sqrt;
466using std::tan;
467using std::tanh;
468
469// MSVC (up to 1930) defines quiet comparison functions as template functions
470// which causes compilation errors due to ambiguity in the template parameter
471// type resolution for using declarations in the ceres namespace. Workaround the
472// issue by defining specific overload and bypass MSVC standard library
473// definitions.
474#if defined(_MSC_VER)
475inline bool isgreater(double lhs,
476 double rhs) noexcept(noexcept(std::isgreater(lhs, rhs))) {
477 return std::isgreater(lhs, rhs);
478}
479inline bool isless(double lhs,
480 double rhs) noexcept(noexcept(std::isless(lhs, rhs))) {
481 return std::isless(lhs, rhs);
482}
483inline bool islessequal(double lhs,
484 double rhs) noexcept(noexcept(std::islessequal(lhs,
485 rhs))) {
486 return std::islessequal(lhs, rhs);
487}
488inline bool isgreaterequal(double lhs, double rhs) noexcept(
489 noexcept(std::isgreaterequal(lhs, rhs))) {
490 return std::isgreaterequal(lhs, rhs);
491}
492inline bool islessgreater(double lhs, double rhs) noexcept(
493 noexcept(std::islessgreater(lhs, rhs))) {
494 return std::islessgreater(lhs, rhs);
495}
496inline bool isunordered(double lhs,
497 double rhs) noexcept(noexcept(std::isunordered(lhs,
498 rhs))) {
499 return std::isunordered(lhs, rhs);
500}
501#else
502using std::isgreater;
504using std::isless;
505using std::islessequal;
507using std::isunordered;
508#endif
509
510#ifdef WOLF_AUTODIFF_HAS_CPP20
511using std::lerp;
512using std::midpoint;
513#endif // defined(WOLF_AUTODIFF_HAS_CPP20)
514
515// Legacy names from pre-C++11 days.
516// clang-format off
517WOLF_AUTODIFF_DEPRECATED_WITH_MSG("wolf::autodiff::IsFinite will be removed in a future Ceres Solver release. Please use wolf::autodiff::isfinite.")
518inline bool IsFinite(double x) { return std::isfinite(x); }
519WOLF_AUTODIFF_DEPRECATED_WITH_MSG("wolf::autodiff::IsInfinite will be removed in a future Ceres Solver release. Please use wolf::autodiff::isinf.")
520inline bool IsInfinite(double x) { return std::isinf(x); }
521WOLF_AUTODIFF_DEPRECATED_WITH_MSG("wolf::autodiff::IsNaN will be removed in a future Ceres Solver release. Please use wolf::autodiff::isnan.")
522inline bool IsNaN(double x) { return std::isnan(x); }
523WOLF_AUTODIFF_DEPRECATED_WITH_MSG("wolf::autodiff::IsNormal will be removed in a future Ceres Solver release. Please use wolf::autodiff::isnormal.")
524inline bool IsNormal(double x) { return std::isnormal(x); }
525// clang-format on
526
527// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
528
529// abs(x + h) ~= abs(x) + sgn(x)h
530template <typename T, int N>
531inline Jet<T, N> abs(const Jet<T, N>& f)
532{
533 return Jet<T, N>(abs(f.a), copysign(T(1), f.a) * f.v);
534}
535
536// copysign(a, b) composes a float with the magnitude of a and the sign of b.
537// Therefore, the function can be formally defined as
538//
539// copysign(a, b) = sgn(b)|a|
540//
541// where
542//
543// d/dx |x| = sgn(x)
544// d/dx sgn(x) = 2δ(x)
545//
546// sgn(x) being the signum function. Differentiating copysign(a, b) with respect
547// to a and b gives:
548//
549// d/da sgn(b)|a| = sgn(a) sgn(b)
550// d/db sgn(b)|a| = 2|a|δ(b)
551//
552// with the dual representation given by
553//
554// copysign(a + da, b + db) ~= sgn(b)|a| + (sgn(a)sgn(b) da + 2|a|δ(b) db)
555//
556// where δ(b) is the Dirac delta function.
557template <typename T, int N>
558inline Jet<T, N> copysign(const Jet<T, N>& f, const Jet<T, N> g)
559{
560 // The Dirac delta function δ(b) is undefined at b=0 (here it's
561 // infinite) and 0 everywhere else.
562 T d = fpclassify(g) == FP_ZERO ? std::numeric_limits<T>::infinity() : T(0);
563 T sa = copysign(T(1), f.a); // sgn(a)
564 T sb = copysign(T(1), g.a); // sgn(b)
565 // The second part of the infinitesimal is 2|a|δ(b) which is either infinity
566 // or 0 unless a or any of the values of the b infinitesimal are 0. In the
567 // latter case, the corresponding values become NaNs (multiplying 0 by
568 // infinity gives NaN). We drop the constant factor 2 since it does not change
569 // the result (its values will still be either 0, infinity or NaN).
570 return Jet<T, N>(copysign(f.a, g.a), sa * sb * f.v + abs(f.a) * d * g.v);
571}
572
573// log(a + h) ~= log(a) + h / a
574template <typename T, int N>
575inline Jet<T, N> log(const Jet<T, N>& f)
576{
577 const T a_inverse = T(1.0) / f.a;
578 return Jet<T, N>(log(f.a), f.v * a_inverse);
579}
580
581// log10(a + h) ~= log10(a) + h / (a log(10))
582template <typename T, int N>
584{
585 // Most compilers will expand log(10) to a constant.
586 const T a_inverse = T(1.0) / (f.a * log(T(10.0)));
587 return Jet<T, N>(log10(f.a), f.v * a_inverse);
588}
589
590// log1p(a + h) ~= log1p(a) + h / (1 + a)
591template <typename T, int N>
593{
594 const T a_inverse = T(1.0) / (T(1.0) + f.a);
595 return Jet<T, N>(log1p(f.a), f.v * a_inverse);
596}
597
598// exp(a + h) ~= exp(a) + exp(a) h
599template <typename T, int N>
600inline Jet<T, N> exp(const Jet<T, N>& f)
601{
602 const T tmp = exp(f.a);
603 return Jet<T, N>(tmp, tmp * f.v);
604}
605
606// expm1(a + h) ~= expm1(a) + exp(a) h
607template <typename T, int N>
609{
610 const T tmp = expm1(f.a);
611 const T expa = tmp + T(1.0); // exp(a) = expm1(a) + 1
612 return Jet<T, N>(tmp, expa * f.v);
613}
614
615// sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
616template <typename T, int N>
617inline Jet<T, N> sqrt(const Jet<T, N>& f)
618{
619 const T tmp = sqrt(f.a);
620 const T two_a_inverse = T(1.0) / (T(2.0) * tmp);
621 return Jet<T, N>(tmp, f.v * two_a_inverse);
622}
623
624// cos(a + h) ~= cos(a) - sin(a) h
625template <typename T, int N>
626inline Jet<T, N> cos(const Jet<T, N>& f)
627{
628 return Jet<T, N>(cos(f.a), -sin(f.a) * f.v);
629}
630
631// acos(a + h) ~= acos(a) - 1 / sqrt(1 - a^2) h
632template <typename T, int N>
633inline Jet<T, N> acos(const Jet<T, N>& f)
634{
635 const T tmp = -T(1.0) / sqrt(T(1.0) - f.a * f.a);
636 return Jet<T, N>(acos(f.a), tmp * f.v);
637}
638
639// sin(a + h) ~= sin(a) + cos(a) h
640template <typename T, int N>
641inline Jet<T, N> sin(const Jet<T, N>& f)
642{
643 return Jet<T, N>(sin(f.a), cos(f.a) * f.v);
644}
645
646// asin(a + h) ~= asin(a) + 1 / sqrt(1 - a^2) h
647template <typename T, int N>
648inline Jet<T, N> asin(const Jet<T, N>& f)
649{
650 const T tmp = T(1.0) / sqrt(T(1.0) - f.a * f.a);
651 return Jet<T, N>(asin(f.a), tmp * f.v);
652}
653
654// tan(a + h) ~= tan(a) + (1 + tan(a)^2) h
655template <typename T, int N>
656inline Jet<T, N> tan(const Jet<T, N>& f)
657{
658 const T tan_a = tan(f.a);
659 const T tmp = T(1.0) + tan_a * tan_a;
660 return Jet<T, N>(tan_a, tmp * f.v);
661}
662
663// atan(a + h) ~= atan(a) + 1 / (1 + a^2) h
664template <typename T, int N>
665inline Jet<T, N> atan(const Jet<T, N>& f)
666{
667 const T tmp = T(1.0) / (T(1.0) + f.a * f.a);
668 return Jet<T, N>(atan(f.a), tmp * f.v);
669}
670
671// sinh(a + h) ~= sinh(a) + cosh(a) h
672template <typename T, int N>
673inline Jet<T, N> sinh(const Jet<T, N>& f)
674{
675 return Jet<T, N>(sinh(f.a), cosh(f.a) * f.v);
676}
677
678// cosh(a + h) ~= cosh(a) + sinh(a) h
679template <typename T, int N>
680inline Jet<T, N> cosh(const Jet<T, N>& f)
681{
682 return Jet<T, N>(cosh(f.a), sinh(f.a) * f.v);
683}
684
685// tanh(a + h) ~= tanh(a) + (1 - tanh(a)^2) h
686template <typename T, int N>
687inline Jet<T, N> tanh(const Jet<T, N>& f)
688{
689 const T tanh_a = tanh(f.a);
690 const T tmp = T(1.0) - tanh_a * tanh_a;
691 return Jet<T, N>(tanh_a, tmp * f.v);
692}
693
694// The floor function should be used with extreme care as this operation will
695// result in a zero derivative which provides no information to the solver.
696//
697// floor(a + h) ~= floor(a) + 0
698template <typename T, int N>
700{
701 return Jet<T, N>(floor(f.a));
702}
703
704// The ceil function should be used with extreme care as this operation will
705// result in a zero derivative which provides no information to the solver.
706//
707// ceil(a + h) ~= ceil(a) + 0
708template <typename T, int N>
709inline Jet<T, N> ceil(const Jet<T, N>& f)
710{
711 return Jet<T, N>(ceil(f.a));
712}
713
714// Some new additions to C++11:
715
716// cbrt(a + h) ~= cbrt(a) + h / (3 a ^ (2/3))
717template <typename T, int N>
718inline Jet<T, N> cbrt(const Jet<T, N>& f)
719{
720 const T derivative = T(1.0) / (T(3.0) * cbrt(f.a * f.a));
721 return Jet<T, N>(cbrt(f.a), f.v * derivative);
722}
723
724// exp2(x + h) = 2^(x+h) ~= 2^x + h*2^x*log(2)
725template <typename T, int N>
726inline Jet<T, N> exp2(const Jet<T, N>& f)
727{
728 const T tmp = exp2(f.a);
729 const T derivative = tmp * log(T(2));
730 return Jet<T, N>(tmp, f.v * derivative);
731}
732
733// log2(x + h) ~= log2(x) + h / (x * log(2))
734template <typename T, int N>
735inline Jet<T, N> log2(const Jet<T, N>& f)
736{
737 const T derivative = T(1.0) / (f.a * log(T(2)));
738 return Jet<T, N>(log2(f.a), f.v * derivative);
739}
740
741// Like sqrt(x^2 + y^2),
742// but acts to prevent underflow/overflow for small/large x/y.
743// Note that the function is non-smooth at x=y=0,
744// so the derivative is undefined there.
745template <typename T, int N>
746inline Jet<T, N> hypot(const Jet<T, N>& x, const Jet<T, N>& y)
747{
748 // d/da sqrt(a) = 0.5 / sqrt(a)
749 // d/dx x^2 + y^2 = 2x
750 // So by the chain rule:
751 // d/dx sqrt(x^2 + y^2) = 0.5 / sqrt(x^2 + y^2) * 2x = x / sqrt(x^2 + y^2)
752 // d/dy sqrt(x^2 + y^2) = y / sqrt(x^2 + y^2)
753 const T tmp = hypot(x.a, y.a);
754 return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v);
755}
756
757// Like sqrt(x^2 + y^2 + z^2),
758// but acts to prevent underflow/overflow for small/large x/y/z.
759// Note that the function is non-smooth at x=y=z=0,
760// so the derivative is undefined there.
761template <typename T, int N>
762inline Jet<T, N> hypot(const Jet<T, N>& x, const Jet<T, N>& y, const Jet<T, N>& z)
763{
764 // d/da sqrt(a) = 0.5 / sqrt(a)
765 // d/dx x^2 + y^2 + z^2 = 2x
766 // So by the chain rule:
767 // d/dx sqrt(x^2 + y^2 + z^2)
768 // = 0.5 / sqrt(x^2 + y^2 + z^2) * 2x
769 // = x / sqrt(x^2 + y^2 + z^2)
770 // d/dy sqrt(x^2 + y^2 + z^2) = y / sqrt(x^2 + y^2 + z^2)
771 // d/dz sqrt(x^2 + y^2 + z^2) = z / sqrt(x^2 + y^2 + z^2)
772 const T tmp = hypot(x.a, y.a, z.a);
773 return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v + z.a / tmp * z.v);
774}
775
776// Like x * y + z but rounded only once.
777template <typename T, int N>
778inline Jet<T, N> fma(const Jet<T, N>& x, const Jet<T, N>& y, const Jet<T, N>& z)
779{
780 // d/dx fma(x, y, z) = y
781 // d/dy fma(x, y, z) = x
782 // d/dz fma(x, y, z) = 1
783 return Jet<T, N>(fma(x.a, y.a, z.a), y.a * x.v + x.a * y.v + z.v);
784}
785
786// Return value of fmax() and fmin() on equality
787// ---------------------------------------------
788//
789// There is arguably no good answer to what fmax() & fmin() should return on
790// equality, which for Jets by definition ONLY compares the scalar parts. We
791// choose what we think is the least worst option (averaging as Jets) which
792// minimises undesirable/unexpected behaviour as used, and also supports client
793// code written against Ceres versions prior to type promotion being supported
794// in Jet comparisons (< v2.1).
795//
796// The std::max() convention of returning the first argument on equality is
797// problematic, as it means that the derivative component may or may not be
798// preserved (when comparing a Jet with a scalar) depending upon the ordering.
799//
800// Always returning the Jet in {Jet, scalar} cases on equality is problematic
801// as it is inconsistent with the behaviour that would be obtained if the scalar
802// was first cast to Jet and the {Jet, Jet} case was used. Prior to type
803// promotion (Ceres v2.1) client code would typically cast constants to Jets
804// e.g: fmax(x, T(2.0)) which means the {Jet, Jet} case predominates, and we
805// still want the result to be order independent.
806//
807// Our intuition is that preserving a non-zero derivative is best, even if
808// its value does not match either of the inputs. Averaging achieves this
809// whilst ensuring argument ordering independence. This is also the approach
810// used by the Jax library, and TensorFlow's reduce_max().
811
812// Returns the larger of the two arguments, with Jet averaging on equality.
813// NaNs are treated as missing data.
814//
815// NOTE: This function is NOT subject to any of the error conditions specified
816// in `math_errhandling`.
817template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
818inline decltype(auto) fmax(const Lhs& x, const Rhs& y)
819{
820 using J = std::common_type_t<Lhs, Rhs>;
821 // As x == y may set FP exceptions in the presence of NaNs when used with
822 // non-default compiler options so we avoid its use here.
823 if (isnan(x) || isnan(y) || islessgreater(x, y))
824 {
825 return isnan(x) || isless(x, y) ? J{y} : J{x};
826 }
827 // x == y (scalar parts) return the average of their Jet representations.
828#if defined(WOLF_AUTODIFF_HAS_CPP20)
829 return midpoint(J{x}, J{y});
830#else
831 return (J{x} + J{y}) * typename J::Scalar(0.5);
832#endif // defined(WOLF_AUTODIFF_HAS_CPP20)
833}
834
835// Returns the smaller of the two arguments, with Jet averaging on equality.
836// NaNs are treated as missing data.
837//
838// NOTE: This function is NOT subject to any of the error conditions specified
839// in `math_errhandling`.
840template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
841inline decltype(auto) fmin(const Lhs& x, const Rhs& y)
842{
843 using J = std::common_type_t<Lhs, Rhs>;
844 // As x == y may set FP exceptions in the presence of NaNs when used with
845 // non-default compiler options so we avoid its use here.
846 if (isnan(x) || isnan(y) || islessgreater(x, y))
847 {
848 return isnan(x) || isgreater(x, y) ? J{y} : J{x};
849 }
850 // x == y (scalar parts) return the average of their Jet representations.
851#if defined(WOLF_AUTODIFF_HAS_CPP20)
852 return midpoint(J{x}, J{y});
853#else
854 return (J{x} + J{y}) * typename J::Scalar(0.5);
855#endif // defined(WOLF_AUTODIFF_HAS_CPP20)
856}
857
858// Returns the positive difference (f - g) of two arguments and zero if f <= g.
859// If at least one argument is NaN, a NaN is return.
860//
861// NOTE At least one of the argument types must be a Jet, the other one can be a
862// scalar. In case both arguments are Jets, their dimensionality must match.
863template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
864inline decltype(auto) fdim(const Lhs& f, const Rhs& g)
865{
866 using J = std::common_type_t<Lhs, Rhs>;
867 if (isnan(f) || isnan(g))
868 {
869 return std::numeric_limits<J>::quiet_NaN();
870 }
871 return isgreater(f, g) ? J{f - g} : J{};
872}
873
874// erf is defined as an integral that cannot be expressed analytically
875// however, the derivative is trivial to compute
876// erf(x + h) = erf(x) + h * 2*exp(-x^2)/sqrt(pi)
877template <typename T, int N>
878inline Jet<T, N> erf(const Jet<T, N>& x)
879{
880 // We evaluate the constant as follows:
881 // 2 / sqrt(pi) = 1 / sqrt(atan(1.))
882 // On POSIX systems it is defined as M_2_SQRTPI, but this is not
883 // portable and the type may not be T. The above expression
884 // evaluates to full precision with IEEE arithmetic and, since it's
885 // constant, the compiler can generate exactly the same code. gcc
886 // does so even at -O0.
887 return Jet<T, N>(erf(x.a), x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
888}
889
890// erfc(x) = 1-erf(x)
891// erfc(x + h) = erfc(x) + h * (-2*exp(-x^2)/sqrt(pi))
892template <typename T, int N>
893inline Jet<T, N> erfc(const Jet<T, N>& x)
894{
895 // See in erf() above for the evaluation of the constant in the derivative.
896 return Jet<T, N>(erfc(x.a), -x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
897}
898
899// Bessel functions of the first kind with integer order equal to 0, 1, n.
900//
901// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
902// _j[0,1,n](). Where available on MSVC, use _j[0,1,n]() to avoid deprecated
903// function errors in client code (the specific warning is suppressed when
904// Ceres itself is built).
905inline double BesselJ0(double x)
906{
908 return j0(x);
910}
911inline double BesselJ1(double x)
912{
914 return j1(x);
916}
917inline double BesselJn(int n, double x)
918{
920 return jn(n, x);
922}
923
924// For the formulae of the derivatives of the Bessel functions see the book:
925// Olver, Lozier, Boisvert, Clark, NIST Handbook of Mathematical Functions,
926// Cambridge University Press 2010.
927//
928// Formulae are also available at http://dlmf.nist.gov
929
930// See formula http://dlmf.nist.gov/10.6#E3
931// j0(a + h) ~= j0(a) - j1(a) h
932template <typename T, int N>
934{
935 return Jet<T, N>(BesselJ0(f.a), -BesselJ1(f.a) * f.v);
936}
937
938// See formula http://dlmf.nist.gov/10.6#E1
939// j1(a + h) ~= j1(a) + 0.5 ( j0(a) - j2(a) ) h
940template <typename T, int N>
942{
943 return Jet<T, N>(BesselJ1(f.a), T(0.5) * (BesselJ0(f.a) - BesselJn(2, f.a)) * f.v);
944}
945
946// See formula http://dlmf.nist.gov/10.6#E1
947// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
948template <typename T, int N>
949inline Jet<T, N> BesselJn(int n, const Jet<T, N>& f)
950{
951 return Jet<T, N>(BesselJn(n, f.a), T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
952}
953
954// Classification and comparison functionality referencing only the scalar part
955// of a Jet. To classify the derivatives (e.g., for sanity checks), the dual
956// part should be referenced explicitly. For instance, to check whether the
957// derivatives of a Jet 'f' are reasonable, one can use
958//
959// isfinite(f.v.array()).all()
960// !isnan(f.v.array()).any()
961//
962// etc., depending on the desired semantics.
963//
964// NOTE: Floating-point classification and comparison functions and operators
965// should be used with care as no derivatives can be propagated by such
966// functions directly but only by expressions resulting from corresponding
967// conditional statements. At the same time, conditional statements can possibly
968// introduce a discontinuity in the cost function making it impossible to
969// evaluate its derivative and thus the optimization problem intractable.
970
971// Determines whether the scalar part of the Jet is finite.
972template <typename T, int N>
973inline bool isfinite(const Jet<T, N>& f)
974{
975 return isfinite(f.a);
976}
977
978// Determines whether the scalar part of the Jet is infinite.
979template <typename T, int N>
980inline bool isinf(const Jet<T, N>& f)
981{
982 return isinf(f.a);
983}
984
985// Determines whether the scalar part of the Jet is NaN.
986template <typename T, int N>
987inline bool isnan(const Jet<T, N>& f)
988{
989 return isnan(f.a);
990}
991
992// Determines whether the scalar part of the Jet is neither zero, subnormal,
993// infinite, nor NaN.
994template <typename T, int N>
995inline bool isnormal(const Jet<T, N>& f)
996{
997 return isnormal(f.a);
998}
999
1000// Determines whether the scalar part of the Jet f is less than the scalar
1001// part of g.
1002//
1003// NOTE: This function does NOT set any floating-point exceptions.
1004template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1005inline bool isless(const Lhs& f, const Rhs& g)
1006{
1007 using internal::AsScalar;
1008 return isless(AsScalar(f), AsScalar(g));
1009}
1010
1011// Determines whether the scalar part of the Jet f is greater than the scalar
1012// part of g.
1013//
1014// NOTE: This function does NOT set any floating-point exceptions.
1015template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1016inline bool isgreater(const Lhs& f, const Rhs& g)
1017{
1018 using internal::AsScalar;
1019 return isgreater(AsScalar(f), AsScalar(g));
1020}
1021
1022// Determines whether the scalar part of the Jet f is less than or equal to the
1023// scalar part of g.
1024//
1025// NOTE: This function does NOT set any floating-point exceptions.
1026template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1027inline bool islessequal(const Lhs& f, const Rhs& g)
1028{
1029 using internal::AsScalar;
1030 return islessequal(AsScalar(f), AsScalar(g));
1031}
1032
1033// Determines whether the scalar part of the Jet f is less than or greater than
1034// (f < g || f > g) the scalar part of g.
1035//
1036// NOTE: This function does NOT set any floating-point exceptions.
1037template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1038inline bool islessgreater(const Lhs& f, const Rhs& g)
1039{
1040 using internal::AsScalar;
1041 return islessgreater(AsScalar(f), AsScalar(g));
1042}
1043
1044// Determines whether the scalar part of the Jet f is greater than or equal to
1045// the scalar part of g.
1046//
1047// NOTE: This function does NOT set any floating-point exceptions.
1048template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1049inline bool isgreaterequal(const Lhs& f, const Rhs& g)
1050{
1051 using internal::AsScalar;
1052 return isgreaterequal(AsScalar(f), AsScalar(g));
1053}
1054
1055// Determines if either of the scalar parts of the arguments are NaN and
1056// thus cannot be ordered with respect to each other.
1057template <typename Lhs, typename Rhs, std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1058inline bool isunordered(const Lhs& f, const Rhs& g)
1059{
1060 using internal::AsScalar;
1061 return isunordered(AsScalar(f), AsScalar(g));
1062}
1063
1064// Categorize scalar part as zero, subnormal, normal, infinite, NaN, or
1065// implementation-defined.
1066template <typename T, int N>
1067inline int fpclassify(const Jet<T, N>& f)
1068{
1069 return fpclassify(f.a);
1070}
1071
1072// Determines whether the scalar part of the argument is negative.
1073template <typename T, int N>
1074inline bool signbit(const Jet<T, N>& f)
1075{
1076 return signbit(f.a);
1077}
1078
1079// Legacy functions from the pre-C++11 days.
1080template <typename T, int N>
1082 "wolf::autodiff::IsFinite will be removed in a future Ceres Solver release. Please "
1083 "use wolf::autodiff::isfinite.")
1084inline bool IsFinite(const Jet<T, N>& f)
1085{
1086 return isfinite(f);
1087}
1088
1089template <typename T, int N>
1091 "wolf::autodiff::IsNaN will be removed in a future Ceres Solver release. Please use "
1092 "wolf::autodiff::isnan.")
1093inline bool IsNaN(const Jet<T, N>& f)
1094{
1095 return isnan(f);
1096}
1097
1098template <typename T, int N>
1100 "wolf::autodiff::IsNormal will be removed in a future Ceres Solver release. Please "
1101 "use wolf::autodiff::isnormal.")
1102inline bool IsNormal(const Jet<T, N>& f)
1103{
1104 return isnormal(f);
1105}
1106
1107// The jet is infinite if any part of the jet is infinite.
1108template <typename T, int N>
1110 "wolf::autodiff::IsInfinite will be removed in a future Ceres Solver release. "
1111 "Please use wolf::autodiff::isinf.")
1112inline bool IsInfinite(const Jet<T, N>& f)
1113{
1114 return isinf(f);
1115}
1116
1117#ifdef WOLF_AUTODIFF_HAS_CPP20
1118// Computes the linear interpolation a + t(b - a) between a and b at the value
1119// t. For arguments outside of the range 0 <= t <= 1, the values are
1120// extrapolated.
1121//
1122// Differentiating lerp(a, b, t) with respect to a, b, and t gives:
1123//
1124// d/da lerp(a, b, t) = 1 - t
1125// d/db lerp(a, b, t) = t
1126// d/dt lerp(a, b, t) = b - a
1127//
1128// with the dual representation given by
1129//
1130// lerp(a + da, b + db, t + dt)
1131// ~= lerp(a, b, t) + (1 - t) da + t db + (b - a) dt .
1132template <typename T, int N>
1133inline Jet<T, N> lerp(const Jet<T, N>& a, const Jet<T, N>& b, const Jet<T, N>& t)
1134{
1135 return Jet<T, N>{lerp(a.a, b.a, t.a), (T(1) - t.a) * a.v + t.a * b.v + (b.a - a.a) * t.v};
1136}
1137
1138// Computes the midpoint a + (b - a) / 2.
1139//
1140// Differentiating midpoint(a, b) with respect to a and b gives:
1141//
1142// d/da midpoint(a, b) = 1/2
1143// d/db midpoint(a, b) = 1/2
1144//
1145// with the dual representation given by
1146//
1147// midpoint(a + da, b + db) ~= midpoint(a, b) + (da + db) / 2 .
1148template <typename T, int N>
1149inline Jet<T, N> midpoint(const Jet<T, N>& a, const Jet<T, N>& b)
1150{
1151 Jet<T, N> result{midpoint(a.a, b.a)};
1152 // To avoid overflow in the differential, compute
1153 // (da + db) / 2 using midpoint.
1154 for (int i = 0; i < N; ++i)
1155 {
1156 result.v[i] = midpoint(a.v[i], b.v[i]);
1157 }
1158 return result;
1159}
1160#endif // defined(WOLF_AUTODIFF_HAS_CPP20)
1161
1162// atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
1163//
1164// In words: the rate of change of theta is 1/r times the rate of
1165// change of (x, y) in the positive angular direction.
1166template <typename T, int N>
1167inline Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f)
1168{
1169 // Note order of arguments:
1170 //
1171 // f = a + da
1172 // g = b + db
1173
1174 T const tmp = T(1.0) / (f.a * f.a + g.a * g.a);
1175 return Jet<T, N>(atan2(g.a, f.a), tmp * (-g.a * f.v + f.a * g.v));
1176}
1177
1178// Computes the square x^2 of a real number x (not the Euclidean L^2 norm as
1179// the name might suggest).
1180//
1181// NOTE: While std::norm is primarily intended for computing the squared
1182// magnitude of a std::complex<> number, the current Jet implementation does not
1183// support mixing a scalar T in its real part and std::complex<T> and in the
1184// infinitesimal. Mixed Jet support is necessary for the type decay from
1185// std::complex<T> to T (the squared magnitude of a complex number is always
1186// real) performed by std::norm.
1187//
1188// norm(x + h) ~= norm(x) + 2x h
1189template <typename T, int N>
1191{
1192 return Jet<T, N>(norm(f.a), T(2) * f.a * f.v);
1193}
1194
1195// pow -- base is a differentiable function, exponent is a constant.
1196// (a+da)^p ~= a^p + p*a^(p-1) da
1197template <typename T, int N>
1198inline Jet<T, N> pow(const Jet<T, N>& f, double g)
1199{
1200 T const tmp = g * pow(f.a, g - T(1.0));
1201 return Jet<T, N>(pow(f.a, g), tmp * f.v);
1202}
1203
1204// pow -- base is a constant, exponent is a differentiable function.
1205// We have various special cases, see the comment for pow(Jet, Jet) for
1206// analysis:
1207//
1208// 1. For f > 0 we have: (f)^(g + dg) ~= f^g + f^g log(f) dg
1209//
1210// 2. For f == 0 and g > 0 we have: (f)^(g + dg) ~= f^g
1211//
1212// 3. For f < 0 and integer g we have: (f)^(g + dg) ~= f^g but if dg
1213// != 0, the derivatives are not defined and we return NaN.
1214
1215template <typename T, int N>
1216inline Jet<T, N> pow(T f, const Jet<T, N>& g)
1217{
1218 Jet<T, N> result;
1219
1220 if (fpclassify(f) == FP_ZERO && g > 0)
1221 {
1222 // Handle case 2.
1223 result = Jet<T, N>(T(0.0));
1224 }
1225 else
1226 {
1227 if (f < 0 && g == floor(g.a))
1228 { // Handle case 3.
1229 result = Jet<T, N>(pow(f, g.a));
1230 for (int i = 0; i < N; i++)
1231 {
1232 if (fpclassify(g.v[i]) != FP_ZERO)
1233 {
1234 // Return a NaN when g.v != 0.
1235 result.v[i] = std::numeric_limits<T>::quiet_NaN();
1236 }
1237 }
1238 }
1239 else
1240 {
1241 // Handle case 1.
1242 T const tmp = pow(f, g.a);
1243 result = Jet<T, N>(tmp, log(f) * tmp * g.v);
1244 }
1245 }
1246
1247 return result;
1248}
1249
1250// pow -- both base and exponent are differentiable functions. This has a
1251// variety of special cases that require careful handling.
1252//
1253// 1. For f > 0:
1254// (f + df)^(g + dg) ~= f^g + f^(g - 1) * (g * df + f * log(f) * dg)
1255// The numerical evaluation of f * log(f) for f > 0 is well behaved, even for
1256// extremely small values (e.g. 1e-99).
1257//
1258// 2. For f == 0 and g > 1: (f + df)^(g + dg) ~= 0
1259// This cases is needed because log(0) can not be evaluated in the f > 0
1260// expression. However the function f*log(f) is well behaved around f == 0
1261// and its limit as f-->0 is zero.
1262//
1263// 3. For f == 0 and g == 1: (f + df)^(g + dg) ~= 0 + df
1264//
1265// 4. For f == 0 and 0 < g < 1: The value is finite but the derivatives are not.
1266//
1267// 5. For f == 0 and g < 0: The value and derivatives of f^g are not finite.
1268//
1269// 6. For f == 0 and g == 0: The C standard incorrectly defines 0^0 to be 1
1270// "because there are applications that can exploit this definition". We
1271// (arbitrarily) decree that derivatives here will be nonfinite, since that
1272// is consistent with the behavior for f == 0, g < 0 and 0 < g < 1.
1273// Practically any definition could have been justified because mathematical
1274// consistency has been lost at this point.
1275//
1276// 7. For f < 0, g integer, dg == 0: (f + df)^(g + dg) ~= f^g + g * f^(g - 1) df
1277// This is equivalent to the case where f is a differentiable function and g
1278// is a constant (to first order).
1279//
1280// 8. For f < 0, g integer, dg != 0: The value is finite but the derivatives are
1281// not, because any change in the value of g moves us away from the point
1282// with a real-valued answer into the region with complex-valued answers.
1283//
1284// 9. For f < 0, g noninteger: The value and derivatives of f^g are not finite.
1285
1286template <typename T, int N>
1287inline Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g)
1288{
1289 Jet<T, N> result;
1290
1291 if (fpclassify(f) == FP_ZERO && g >= 1)
1292 {
1293 // Handle cases 2 and 3.
1294 if (g > 1)
1295 {
1296 result = Jet<T, N>(T(0.0));
1297 }
1298 else
1299 {
1300 result = f;
1301 }
1302 }
1303 else
1304 {
1305 if (f < 0 && g == floor(g.a))
1306 {
1307 // Handle cases 7 and 8.
1308 T const tmp = g.a * pow(f.a, g.a - T(1.0));
1309 result = Jet<T, N>(pow(f.a, g.a), tmp * f.v);
1310 for (int i = 0; i < N; i++)
1311 {
1312 if (fpclassify(g.v[i]) != FP_ZERO)
1313 {
1314 // Return a NaN when g.v != 0.
1315 result.v[i] = T(std::numeric_limits<double>::quiet_NaN());
1316 }
1317 }
1318 }
1319 else
1320 {
1321 // Handle the remaining cases. For cases 4,5,6,9 we allow the log()
1322 // function to generate -HUGE_VAL or NaN, since those cases result in a
1323 // nonfinite derivative.
1324 T const tmp1 = pow(f.a, g.a);
1325 T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
1326 T const tmp3 = tmp1 * log(f.a);
1327 result = Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
1328 }
1329 }
1330
1331 return result;
1332}
1333
1334// Note: This has to be in the ceres namespace for argument dependent lookup to
1335// function correctly. Otherwise statements like CHECK_LE(x, 2.0) fail with
1336// strange compile errors.
1337template <typename T, int N>
1338inline std::ostream& operator<<(std::ostream& s, const Jet<T, N>& z)
1339{
1340 s << "[" << z.a << " ; ";
1341 for (int i = 0; i < N; ++i)
1342 {
1343 s << z.v[i];
1344 if (i != N - 1)
1345 {
1346 s << ", ";
1347 }
1348 }
1349 s << "]";
1350 return s;
1351}
1352} // namespace wolf::autodiff
1353
1354namespace std
1355{
1356template <typename T, int N>
1357struct numeric_limits<wolf::autodiff::Jet<T, N>>
1358{
1359 static constexpr bool is_specialized = true;
1360 static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
1361 static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
1362 static constexpr bool is_exact = std::numeric_limits<T>::is_exact;
1363 static constexpr bool has_infinity = std::numeric_limits<T>::has_infinity;
1364 static constexpr bool has_quiet_NaN = std::numeric_limits<T>::has_quiet_NaN;
1365 static constexpr bool has_signaling_NaN = std::numeric_limits<T>::has_signaling_NaN;
1366 static constexpr bool is_iec559 = std::numeric_limits<T>::is_iec559;
1367 static constexpr bool is_bounded = std::numeric_limits<T>::is_bounded;
1368 static constexpr bool is_modulo = std::numeric_limits<T>::is_modulo;
1369
1370 // has_denorm (and has_denorm_loss, not defined for Jet) has been deprecated
1371 // in C++23. However, without an intent to remove the declaration. Disable
1372 // deprecation warnings temporarily just for the corresponding symbols.
1374 static constexpr std::float_denorm_style has_denorm = std::numeric_limits<T>::has_denorm;
1376 static constexpr std::float_round_style round_style = std::numeric_limits<T>::round_style;
1377
1378 static constexpr int digits = std::numeric_limits<T>::digits;
1379 static constexpr int digits10 = std::numeric_limits<T>::digits10;
1380 static constexpr int max_digits10 = std::numeric_limits<T>::max_digits10;
1381 static constexpr int radix = std::numeric_limits<T>::radix;
1382 static constexpr int min_exponent = std::numeric_limits<T>::min_exponent;
1383 static constexpr int min_exponent10 = std::numeric_limits<T>::max_exponent10;
1384 static constexpr int max_exponent = std::numeric_limits<T>::max_exponent;
1385 static constexpr int max_exponent10 = std::numeric_limits<T>::max_exponent10;
1386 static constexpr bool traps = std::numeric_limits<T>::traps;
1387 static constexpr bool tinyness_before = std::numeric_limits<T>::tinyness_before;
1388
1390 {
1391 return wolf::autodiff::Jet<T, N>((std::numeric_limits<T>::min)());
1392 }
1393 static constexpr wolf::autodiff::Jet<T, N> lowest() noexcept
1394 {
1395 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::lowest());
1396 }
1397 static constexpr wolf::autodiff::Jet<T, N> epsilon() noexcept
1398 {
1399 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::epsilon());
1400 }
1401 static constexpr wolf::autodiff::Jet<T, N> round_error() noexcept
1402 {
1403 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::round_error());
1404 }
1405 static constexpr wolf::autodiff::Jet<T, N> infinity() noexcept
1406 {
1407 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::infinity());
1408 }
1409 static constexpr wolf::autodiff::Jet<T, N> quiet_NaN() noexcept
1410 {
1411 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::quiet_NaN());
1412 }
1413 static constexpr wolf::autodiff::Jet<T, N> signaling_NaN() noexcept
1414 {
1415 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::signaling_NaN());
1416 }
1417 static constexpr wolf::autodiff::Jet<T, N> denorm_min() noexcept
1418 {
1419 return wolf::autodiff::Jet<T, N>(std::numeric_limits<T>::denorm_min());
1420 }
1421
1423 {
1424 return wolf::autodiff::Jet<T, N>((std::numeric_limits<T>::max)());
1425 }
1426};
1427
1428} // namespace std
1429
1430namespace Eigen
1431{
1432// Creating a specialization of NumTraits enables placing Jet objects inside
1433// Eigen arrays, getting all the goodness of Eigen combined with autodiff.
1434template <typename T, int N>
1435struct NumTraits<wolf::autodiff::Jet<T, N>>
1436{
1441
1443 {
1444 return wolf::autodiff::Jet<T, N>(1e-12);
1445 }
1446
1447 static inline Real epsilon()
1448 {
1449 return Real(std::numeric_limits<T>::epsilon());
1450 }
1451
1452 static inline int digits10()
1453 {
1454 return NumTraits<T>::digits10();
1455 }
1456 static inline int max_digits10()
1457 {
1458 return NumTraits<T>::max_digits10();
1459 }
1460
1461 enum
1462 {
1463 IsComplex = 0,
1464 IsInteger = 0,
1466 ReadCost = 1,
1467 AddCost = 1,
1468 // For Jet types, multiplication is more expensive than addition.
1469 MulCost = 3,
1470 HasFloatingPoint = 1,
1471 RequireInitialization = 1
1473
1474 template <bool Vectorized>
1475 struct Div
1476 {
1477 enum
1478 {
1479#if defined(EIGEN_VECTORIZE_AVX)
1480 AVX = true,
1481#else
1482 AVX = false,
1483#endif
1484
1485 // Assuming that for Jets, division is as expensive as
1486 // multiplication.
1487 Cost = 3
1489 };
1490
1491 static inline Real highest()
1492 {
1493 return Real((std::numeric_limits<T>::max)());
1494 }
1495 static inline Real lowest()
1496 {
1497 return Real(-(std::numeric_limits<T>::max)());
1498 }
1499};
1500
1501// Specifying the return type of binary operations between Jets and scalar types
1502// allows you to perform matrix/array operations with Eigen matrices and arrays
1503// such as addition, subtraction, multiplication, and division where one Eigen
1504// matrix/array is of type Jet and the other is a scalar type. This improves
1505// performance by using the optimized scalar-to-Jet binary operations but
1506// is only available on Eigen versions >= 3.3
1507template <typename BinaryOp, typename T, int N>
1508struct ScalarBinaryOpTraits<wolf::autodiff::Jet<T, N>, T, BinaryOp>
1509{
1511};
1512template <typename BinaryOp, typename T, int N>
1513struct ScalarBinaryOpTraits<T, wolf::autodiff::Jet<T, N>, BinaryOp>
1514{
1516};
1517
1518} // namespace Eigen
1519
1520#endif // WOLF_AUTODIFF_PUBLIC_JET_H_
Namespace extending Eigen definitions.
Definition: wolf.h:94
Definition: jet.h:1355
constexpr decltype(auto) AsScalar(T &&value) noexcept
Definition: jet_traits.h:112
Definition: integer_sequence_algorithm.h:50
Jet< T, N > cbrt(const Jet< T, N > &f)
Definition: jet.h:718
Jet< T, N > abs(const Jet< T, N > &f)
Definition: jet.h:531
Jet< T, N > operator*(const Jet< T, N > &f, const Jet< T, N > &g)
Definition: jet.h:356
Jet< T, N > log10(const Jet< T, N > &f)
Definition: jet.h:583
Jet< T, N > asin(const Jet< T, N > &f)
Definition: jet.h:648
decltype(auto) fmin(const Lhs &x, const Rhs &y)
Definition: jet.h:841
bool IsNormal(double x)
Definition: jet.h:524
Jet< T, N > expm1(const Jet< T, N > &f)
Definition: jet.h:608
Jet< T, N > log2(const Jet< T, N > &f)
Definition: jet.h:735
bool isgreaterequal(const Lhs &f, const Rhs &g)
Definition: jet.h:1049
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:641
Jet< T, N > erfc(const Jet< T, N > &x)
Definition: jet.h:893
bool IsInfinite(double x)
Definition: jet.h:520
bool IsNaN(double x)
Definition: jet.h:522
Jet< T, N > tanh(const Jet< T, N > &f)
Definition: jet.h:687
Jet< T, N > operator/(const Jet< T, N > &f, const Jet< T, N > &g)
Definition: jet.h:374
Jet< T, N > const & operator+(const Jet< T, N > &f)
Definition: jet.h:305
Jet< T, N > copysign(const Jet< T, N > &f, const Jet< T, N > g)
Definition: jet.h:558
bool isnormal(const Jet< T, N > &f)
Definition: jet.h:995
double BesselJ0(double x)
Definition: jet.h:905
bool islessgreater(const Lhs &f, const Rhs &g)
Definition: jet.h:1038
decltype(auto) fdim(const Lhs &f, const Rhs &g)
Definition: jet.h:864
N & f
Definition: jet.h:1085
bool isfinite(const Jet< T, N > &f)
Definition: jet.h:973
bool isunordered(const Lhs &f, const Rhs &g)
Definition: jet.h:1058
Jet< T, N > tan(const Jet< T, N > &f)
Definition: jet.h:656
Jet< T, N > floor(const Jet< T, N > &f)
Definition: jet.h:699
double BesselJn(int n, double x)
Definition: jet.h:917
Jet< T, N > atan(const Jet< T, N > &f)
Definition: jet.h:665
bool islessequal(const Lhs &f, const Rhs &g)
Definition: jet.h:1027
Jet< T, N > exp(const Jet< T, N > &f)
Definition: jet.h:600
bool isless(const Lhs &f, const Rhs &g)
Definition: jet.h:1005
bool signbit(const Jet< T, N > &f)
Definition: jet.h:1074
Jet< T, N > cosh(const Jet< T, N > &f)
Definition: jet.h:680
Jet< T, N > fma(const Jet< T, N > &x, const Jet< T, N > &y, const Jet< T, N > &z)
Definition: jet.h:778
int fpclassify(const Jet< T, N > &f)
Definition: jet.h:1067
WOLF_AUTODIFF_DEPRECATED_WITH_MSG("wolf::autodiff::IsFinite will be removed in a future Ceres Solver release. Please " "use wolf::autodiff::isfinite.") inline bool IsFinite(const Jet< T
double BesselJ1(double x)
Definition: jet.h:911
Jet< T, N > atan2(const Jet< T, N > &g, const Jet< T, N > &f)
Definition: jet.h:1167
Jet< T, N > erf(const Jet< T, N > &x)
Definition: jet.h:878
std::ostream & operator<<(std::ostream &s, const Jet< T, N > &z)
Definition: jet.h:1338
Jet< T, N > operator-(const Jet< T, N > &f)
Definition: jet.h:314
bool IsFinite(double x)
Definition: jet.h:518
Jet< T, N > norm(const Jet< T, N > &f)
Definition: jet.h:1190
Jet< T, N > log1p(const Jet< T, N > &f)
Definition: jet.h:592
Jet< T, N > hypot(const Jet< T, N > &x, const Jet< T, N > &y)
Definition: jet.h:746
bool isnan(const Jet< T, N > &f)
Definition: jet.h:987
bool isinf(const Jet< T, N > &f)
Definition: jet.h:980
Jet< T, N > log(const Jet< T, N > &f)
Definition: jet.h:575
WOLF_AUTODIFF_DEFINE_JET_COMPARISON_OPERATOR(<) WOLF_AUTODIFF_DEFINE_JET_COMPARISON_OPERATOR(<
Jet< T, N > exp2(const Jet< T, N > &f)
Definition: jet.h:726
decltype(auto) fmax(const Lhs &x, const Rhs &y)
Definition: jet.h:818
Jet< T, N > pow(const Jet< T, N > &f, const Jet< T, N > &g)
Definition: jet.h:1287
Jet< T, N > pow(const Jet< T, N > &f, double g)
Definition: jet.h:1198
bool isgreater(const Lhs &f, const Rhs &g)
Definition: jet.h:1016
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:617
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:626
Jet< T, N > ceil(const Jet< T, N > &f)
Definition: jet.h:709
Jet< T, N > acos(const Jet< T, N > &f)
Definition: jet.h:633
Jet< T, N > sinh(const Jet< T, N > &f)
Definition: jet.h:673
Jet< T, N > hypot(const Jet< T, N > &x, const Jet< T, N > &y, const Jet< T, N > &z)
Definition: jet.h:762
Definition: capture_base.h:23
#define WOLF_AUTODIFF_DISABLE_DEPRECATED_WARNING
Definition: port.h:94
#define WOLF_AUTODIFF_RESTORE_DEPRECATED_WARNING
Definition: port.h:95
static int digits10()
Definition: jet.h:1452
static Real highest()
Definition: jet.h:1491
static int max_digits10()
Definition: jet.h:1456
static wolf::autodiff::Jet< T, N > dummy_precision()
Definition: jet.h:1442
static Real epsilon()
Definition: jet.h:1447
static Real lowest()
Definition: jet.h:1495
static constexpr wolf::autodiff::Jet< T, N > min WOLF_AUTODIFF_PREVENT_MACRO_SUBSTITUTION() noexcept
Definition: jet.h:1389
static constexpr wolf::autodiff::Jet< T, N > max WOLF_AUTODIFF_PREVENT_MACRO_SUBSTITUTION() noexcept
Definition: jet.h:1422
static constexpr wolf::autodiff::Jet< T, N > lowest() noexcept
Definition: jet.h:1393
static constexpr wolf::autodiff::Jet< T, N > signaling_NaN() noexcept
Definition: jet.h:1413
static constexpr wolf::autodiff::Jet< T, N > epsilon() noexcept
Definition: jet.h:1397
static constexpr wolf::autodiff::Jet< T, N > infinity() noexcept
Definition: jet.h:1405
static constexpr wolf::autodiff::Jet< T, N > denorm_min() noexcept
Definition: jet.h:1417
static constexpr wolf::autodiff::Jet< T, N > quiet_NaN() noexcept
Definition: jet.h:1409
static constexpr wolf::autodiff::Jet< T, N > round_error() noexcept
Definition: jet.h:1401
Definition: jet.h:218
Jet< T, N > & operator*=(const T &s)
Definition: jet.h:282
Jet< T, N > & operator/=(const Jet< T, N > &y)
Definition: jet.h:266
T a
Definition: jet.h:293
Jet< T, N > & operator*=(const Jet< T, N > &y)
Definition: jet.h:261
EIGEN_STRONG_INLINE Jet(const T &a, const Eigen::DenseBase< Derived > &v)
Definition: jet.h:247
Jet< T, N > & operator/=(const T &s)
Definition: jet.h:287
Jet< T, N > & operator+=(const Jet< T, N > &y)
Definition: jet.h:251
Jet< T, N > & operator+=(const T &s)
Definition: jet.h:272
Jet()
Definition: jet.h:227
Jet(const T &value)
Definition: jet.h:230
@ DIMENSION
Definition: jet.h:219
Jet< T, N > & operator-=(const Jet< T, N > &y)
Definition: jet.h:256
T Scalar
Definition: jet.h:220
Jet(const T &value, int k)
Definition: jet.h:236
Eigen::Matrix< T, N, 1 > v
Definition: jet.h:296
Jet< T, N > & operator-=(const T &s)
Definition: jet.h:277